#include "juliaSprite.h"
#include "app/application.h"
#include "components/3D/sweety_3D_Camera.h"
#include "framework/sweety_Render.h"

#define SHADER_PATH "Shaders/"

namespace SW
{
    JuliaSprite::JuliaSprite()
    {
        float vtx[] = { -1.0f, -1.0f, 0.f,
                        1.0f,  -1.0f, 0.f,
                        1.0f,   1.0f, 0.f,
                       -1.0f,   1.0f, 0.f };



        if (nullptr == m_VaoPtr)
        {
            m_VaoPtr = new VaoClass(vtx, sizeof(vtx), 3);
        }

        InitShaders();
    }

    JuliaSprite::~JuliaSprite()
    {
        if (m_VaoPtr)
        {
            delete m_VaoPtr;
            m_VaoPtr = nullptr;
        }
    }

    void JuliaSprite::InitShaders()
    {
        m_Shader.useVertex(); m_Shader.useFragment();

#ifdef __EMSCRIPTEN__
        m_Shader.getVertex()->Load("#version 300 es\n", 1, SHADER_PATH "qjVert.glsl");
        m_Shader.getFragment()->Load("#version 300 es\n", 1, SHADER_PATH "qjFragES2.glsl");
#else
#ifdef GLAPP_NO_GLSL_PIPELINE
        m_Shader.getVertex()->Load("#version 410\n", 1, SHADER_PATH "qjVert.glsl");
#else
        m_Shader.getVertex()->Load("#version 410\n#define QJSET_USE_PIPELINE\n", 1, SHADER_PATH "qjVert.glsl");
#endif

        m_Shader.getFragment()->Load("#version 410\n", 1, SHADER_PATH "qjFragES2.glsl");
#endif
        // The vertex and fragment are added to the program object
        m_Shader.addVertex();
        m_Shader.addFragment();

        m_Shader.link();

        m_Shader.bindPipeline();
        m_Shader.useProgram();

        _Resolution             = m_Shader.getUniformLocation("resolution");
        _quatPt                 = m_Shader.getUniformLocation("quatPt");
        _diffuseColor           = m_Shader.getUniformLocation("diffuseColor");
        _phongMethod            = m_Shader.getUniformLocation("phongMethod");
        _specularExponent       = m_Shader.getUniformLocation("specularExponent");
        _specularComponent      = m_Shader.getUniformLocation("specularComponent");
        _normalComponent        = m_Shader.getUniformLocation("normalComponent");
        _isFullRender           = m_Shader.getUniformLocation("isFullRender");
        _useShadow              = m_Shader.getUniformLocation("useShadow");
        _useAO                  = m_Shader.getUniformLocation("useAO");
        _matOrientation         = m_Shader.getUniformLocation("matOrientation");
        _Light                  = m_Shader.getUniformLocation("Light");
        _epsilon                = m_Shader.getUniformLocation("epsilon");
        _position               = m_Shader.getUniformLocation("position");

        m_Shader.reset();
    }

    void JuliaSprite::Render(const mat4& modelTrans)
    {
        if (nullptr == m_VaoPtr)
        {
            return;
        }

        m_Shader.bindPipeline();
        m_Shader.useProgram();
        m_VaoPtr->bindVao();

        if (0 == mWidth || 0 == mHeight)
        {
            mWidth = SW::Application::GetInstance()->GetInitializationSize().x;
            mHeight = SW::Application::GetInstance()->GetInitializationSize().y;
        }

        Camera3D* camera = dynamic_cast<Camera3D*>(Renderer::GetCurrentCamera());
        if (camera)
        {
            position = camera->GetPosition();
        }

        mat4 mvTrans = camera->GetViewTrans() * modelTrans;
        mat3 normalTrans = transpose(inverse(mat3(mvTrans)));

        glUniform4fv(_quatPt, 1, value_ptr(quatPt));
        glUniform3fv(_Resolution, 1, value_ptr(vec3(mWidth, mHeight, float(mWidth) / float(mHeight))));
        glUniform3fv(_diffuseColor, 1, value_ptr(diffuseColor));
        glUniform3fv(_Light, 1, value_ptr(Light));

        glUniform1f(_phongMethod, phongMethod);
        glUniform1f(_specularExponent, specularExponent);
        glUniform1f(_specularComponent, specularComponent);
        glUniform1f(_normalComponent, normalComponent);
        glUniform1f(_epsilon, epsilon);

        glUniform1i(_isFullRender, isFullRender);
        glUniform1i(_useShadow, useShadow);
        glUniform1i(_useAO, useAO);

        glUniform3fv(_position, 1, value_ptr(position));

        glUniformMatrix3fv(_matOrientation, 1, GL_FALSE, value_ptr(transpose(normalTrans)));

        m_VaoPtr->draw(false, true);

        m_Shader.reset();
    }

    void JuliaSprite::SetSize(int w, int h)
    {
        mWidth = w;
        mHeight = h;
    }
}
